package com.gmail.hh.flickrj.sample.android.data;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.widget.ImageView;
import android.widget.Toast;

import com.gmail.hh.flickrj.sample.android.fragments.FragmentHeaderUser.IRefreshHeaderUserListener;
import com.gmail.hh.flickrj.sample.android.helper.SettingsManager;
import com.gmail.hh.flickrj.sample.android.interfaces.IDataReadyListener;
import com.gmail.hh.flickrj.sample.android.tasks.GetOAuthTokenTask;
import com.gmail.hh.flickrj.sample.android.tasks.LoadContactsTask;
import com.gmail.hh.flickrj.sample.android.tasks.LoadContactsTask.IContactsLoadedListener;
import com.gmail.hh.flickrj.sample.android.tasks.LoadImageTask;
import com.gmail.hh.flickrj.sample.android.tasks.LoadImageTask.IImageLoadedListener;
import com.gmail.hh.flickrj.sample.android.tasks.LoadPhotostreamTask;
import com.gmail.hh.flickrj.sample.android.tasks.LoadPhotostreamTask.IPhotostreamLoadedListener;
import com.gmail.hh.flickrj.sample.android.tasks.LoadUserForContactsTask;
import com.gmail.hh.flickrj.sample.android.tasks.LoadUserForContactsTask.IUserLoadedListener;
import com.gmail.hh.flickrj.sample.android.tasks.LoadUserTask;
import com.gmail.hh.flickrj.sample.android.tasks.OAuthTask;
import com.gmail.hh.flickrj.sample.android.tasks.UploadPhotoTask;
import com.gmail.hh.flickrj.sample.android.tasks.UploadPhotoTask.IPhotoUploadedListener;
import com.googlecode.flickrjandroid.contacts.Contact;
import com.googlecode.flickrjandroid.oauth.OAuth;
import com.googlecode.flickrjandroid.oauth.OAuthToken;
import com.googlecode.flickrjandroid.people.User;
import com.googlecode.flickrjandroid.photos.PhotoList;
//TODO make a configuration manager for statics


public class DataManagerFlickr implements
									IPhotostreamLoadedListener,
									IContactsLoadedListener,
									IPhotoUploadedListener,
									IUserLoadedListener,
									IImageLoadedListener {

	private static final Logger logger = LoggerFactory.getLogger(DataManagerFlickr.class);
	
	public static final String CALLBACK_SCHEME = "flickrj-android-sample-oauth"; //$NON-NLS-1$
	public static final String PREFS_NAME = "flickrj-android-sample-pref"; //$NON-NLS-1$
	public static final String KEY_OAUTH_TOKEN = "flickrj-android-oauthToken"; //$NON-NLS-1$
	public static final String KEY_TOKEN_SECRET = "flickrj-android-tokenSecret"; //$NON-NLS-1$
	public static final String KEY_USER_NAME = "flickrj-android-userName"; //$NON-NLS-1$
	public static final String KEY_USER_ID = "flickrj-android-userId"; //$NON-NLS-1$
	
	
	private static DataManagerFlickr instance = null;
	private static Context context = null;
	private boolean oauthRequestStarted = false;

	// callbacks
	IDataReadyListener callbackLoadUserLogin;
	IDataReadyListener callbackLoadUserDisplayed;
	IDataReadyListener callbackLoadPhotostreamUser;
	IDataReadyListener callbackUploadPhoto;
	IDataReadyListener callbackLoadContacts;
	IDataReadyListener callbackUserForContacts;
	
	//Data Store
	private User userLogin;
	private User userDisplayed;
	private PhotolistData photolistDataUser;
	private String resultUpload;
	private Collection<User> contactsUser;
	private User userForContacts;
	
	
	private DataManagerFlickr() {
	}

	public static DataManagerFlickr getInstance() {
		if (instance == null) {
			instance = new DataManagerFlickr();
		}
		return instance;
	}

	public void initializeContext(Context context) {
		this.context = context;
	}
	
	
	
	// do OAuth-Authentification when try to load User
	public void loadUserLogin(IDataReadyListener callback, ImageView userIcon) {
    	logger.error("UserLogin - load"); 
		this.callbackLoadUserLogin = callback;
		OAuth oauth = getOAuthToken();
		if (oauth == null || oauth.getUser() == null) {
			if ( !oauthRequestStarted ) {
				oauthRequestStarted = true;
				OAuthTask task = new OAuthTask(context);
				task.execute();
			}
		} else {
    		if (userIcon == null) {
        	logger.error("Icon: ist NULL!!!"); 
    		} 
    		String userId = oauth.getUser().getId();
			new LoadUserTask(context, LoadUserTask.USERTYPE_LOGIN, userId, userIcon).execute(oauth);
		}
	}
	// methods set... invoked when load...()-task was successful
	public void setUserLogin(User user) {
    	logger.error("UserLogin - set"); 
		this.userLogin = user;
		// set also into userDisplayed 
		this.userDisplayed = user;   
		if (callbackLoadUserLogin != null ) {
			callbackLoadUserLogin.onDataReady(true);
		} 
	}	
	// return User from Data-Store
	public User getUserLogin() {
		return userLogin;
	}

	
	
	// load User Displayed
	public void loadUserDisplayed(IDataReadyListener callback, ImageView userIcon) {
		this.callbackLoadUserDisplayed = callback;
		OAuth oauth = getOAuthToken();
		String userId = null;
		if (oauth != null && oauth.getUser() != null) {
			userId = oauth.getUser().getId();  // default is login-user
		}
		if (userDisplayed != null ) {
			userId = userDisplayed.getId();
		}
		if (oauth != null && oauth.getUser() != null) {
			new LoadUserTask(context, LoadUserTask.USERTYPE_DISPLAYED, userId, userIcon).execute(oauth);
		}
	}
	// methods set... invoked when load...()-task was successful
	public void setUserDisplayed(User user) {
		this.userDisplayed = user;
		if (callbackLoadUserDisplayed != null ) {
			callbackLoadUserDisplayed.onDataReady(true);
		} 
	}	
	// return User from Data-Store
	public User getUserDisplayed() {
		return userDisplayed;
	}
	

	
	
	
	public void loadPhotostreamUser(IDataReadyListener callback) {
		this.callbackLoadPhotostreamUser = callback;
		OAuth oauth = getOAuthToken();
		if (oauth != null && oauth.getUser() != null) {
			String userId = oauth.getUser().getId();  // default is login-user
			if (userDisplayed != null ) {
				userId = userDisplayed.getId();
			}
			new LoadPhotostreamTask(this, userId).execute(oauth);
		}
	}
	// callback method after loadPhotolist asynchron
	@Override
	public void onPhotostreamLoaded(PhotoList photolist) {
		// replace only when object was returned
		if (photolist!= null) {
			photolistDataUser = new PhotolistData();
			photolistDataUser.putPhotolist(photolist);
		} 
		if (callbackLoadPhotostreamUser != null ) {
			callbackLoadPhotostreamUser.onDataReady(true);
		} 
	}
	// return PhotolistData from Data-Store
	public PhotolistData getPhotolistDataUser() {
		return photolistDataUser;
	}
	
	
	public void loadContacts(IDataReadyListener callback) {
		this.callbackLoadContacts = callback;
		OAuth oauth = getOAuthToken();
		if (oauth != null && oauth.getUser() != null) {
			new LoadContactsTask(this).execute(oauth);
		}
	}
	// callback method after loadContacts asynchron
	@Override
	public void onContactsLoaded(Collection<User> contactsUser) {
		// replace only when object was returned
		if (contactsUser!= null) {
			this.contactsUser = contactsUser;
		} 
		if (callbackLoadContacts != null ) {
			callbackLoadContacts.onDataReady(true);
		} 
	}
	// return Contacts from Data-Store
	public Collection<User> getContactsUserIncludingLoginUser() {
		Collection<User> contactsIncl = new ArrayList<User>();
		if (userLogin!= null) {
			contactsIncl.add(userLogin);
			if (contactsUser!= null) {
				contactsIncl.addAll(contactsUser);
			}
		}
		return contactsIncl;
	}

	
	// find a user for Contacts 
	public void findUserForContacts(IDataReadyListener callback, String searchUsername) {
		this.userForContacts=null;  // reset
		this.callbackUserForContacts = callback;
		OAuth oauth = getOAuthToken();
		if (oauth != null && oauth.getUser() != null) {
			new LoadUserForContactsTask(this, searchUsername).execute(oauth);
		}
	}
	// callback method after loadUser asynchron
	@Override
	public void onUserLoaded(User user) {
		this.userForContacts = user;
		if (callbackUserForContacts != null ) {
			callbackUserForContacts.onDataReady(true);
		} 
	}
	// return user from Data-Store
	public User getUserForContacts() {
		return userForContacts;
	}
	

	
	
	public LoadImageTask loadPhotoImageMedium(PhotoData photoData, boolean showProgress, long delayMSEC) {
		OAuth oauth = getOAuthToken();
		LoadImageTask task = null;
		if (oauth != null && oauth.getUser() != null) {
	        if (photoData != null && photoData.getImageViewMedium()!=null) {
	        	// load large Image
	        	task = new LoadImageTask(this, delayMSEC, photoData, photoData.getImageViewMedium(), showProgress, context);
//	            Drawable drawable = new DownloadedDrawable(task);
//	            photoData.getImageView().setImageDrawable(drawable);
	            task.execute(photoData.getPhoto().getMediumUrl());
	            return task;
	        }
        }
        return task;
	}	
	// callback method after loadImage asynchron
	@Override
	public void onImageLoaded(PhotoData photoData) {
		if (photoData!=null) {
			String imageCenterRot = SettingsManager.getInstance().getImageCenterRot();
			photoData.centerMatrix(imageCenterRot, photoData.getImageViewMedium());
		}
		
	}
	
	
	

    public void onOAuthDone(OAuth result) {
		if (result == null) {
			Toast.makeText(context,
					"Authorization failed", //$NON-NLS-1$
					Toast.LENGTH_LONG).show();
		} else {
			User user = result.getUser();
			OAuthToken token = result.getToken();
			if (user == null || user.getId() == null || token == null
					|| token.getOauthToken() == null
					|| token.getOauthTokenSecret() == null) {
				Toast.makeText(context,
						"Authorization failed", //$NON-NLS-1$
						Toast.LENGTH_LONG).show();
				return;
			}
			String message = String.format(Locale.US, "Authorization Succeed: user=%s, userId=%s, oauthToken=%s, tokenSecret=%s", //$NON-NLS-1$
					user.getUsername(), user.getId(), token.getOauthToken(), token.getOauthTokenSecret());
			Toast.makeText(context,
					message,
					Toast.LENGTH_LONG).show();
			saveOAuthToken(user.getUsername(), user.getId(), token.getOauthToken(), token.getOauthTokenSecret());
			oauthRequestStarted = false; // reset flag
			// load Login-User
			loadUserLogin(callbackLoadUserLogin, null);
		}
	}
    
    
    public OAuth getOAuthToken() {
    	 //Restore preferences
        SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        String oauthTokenString = settings.getString(KEY_OAUTH_TOKEN, null);
        String tokenSecret = settings.getString(KEY_TOKEN_SECRET, null);
        if (oauthTokenString == null && tokenSecret == null) {
        	logger.warn("No oauth token retrieved"); //$NON-NLS-1$
        	return null;
        }
        OAuth oauth = new OAuth();
        String userName = settings.getString(KEY_USER_NAME, null);
        String userId = settings.getString(KEY_USER_ID, null);
        if (userId != null) {
        	User user = new User();
        	user.setUsername(userName);
        	user.setId(userId);
        	oauth.setUser(user);
        }
        OAuthToken oauthToken = new OAuthToken();
        oauth.setToken(oauthToken);
        oauthToken.setOauthToken(oauthTokenString);
        oauthToken.setOauthTokenSecret(tokenSecret);
        logger.debug("Retrieved token from preference store: oauth token={}, and token secret={}", oauthTokenString, tokenSecret); //$NON-NLS-1$
        return oauth;
    }
    
	public void retrieveOAuthToken(IDataReadyListener callback, Intent intent) {
		callbackLoadUserLogin = callback;
		String scheme = intent.getScheme();   // onNewIntent is important!
		OAuth savedToken = getOAuthToken(); 
		if (CALLBACK_SCHEME.equals(scheme) && (savedToken == null || savedToken.getUser() == null)) {
			Uri uri = intent.getData();
			String query = uri.getQuery();
			logger.debug("Returned Query: {}", query); //$NON-NLS-1$
			String[] data = query.split("&"); //$NON-NLS-1$
			if (data != null && data.length == 2) {
				String oauthToken = data[0].substring(data[0].indexOf("=") + 1); //$NON-NLS-1$
				String oauthVerifier = data[1]
						.substring(data[1].indexOf("=") + 1); //$NON-NLS-1$
				logger.debug("OAuth Token: {}; OAuth Verifier: {}", oauthToken, oauthVerifier); //$NON-NLS-1$

				OAuth oauth = getOAuthToken();
				if (oauth != null && oauth.getToken() != null && oauth.getToken().getOauthTokenSecret() != null) {
					GetOAuthTokenTask task = new GetOAuthTokenTask();
					task.execute(oauthToken, oauth.getToken().getOauthTokenSecret(), oauthVerifier);
				}
			}
		}

	}
    
    
    public void saveOAuthToken(String userName, String userId, String token, String tokenSecret) {
    	logger.debug("Saving userName=%s, userId=%s, oauth token={}, and token secret={}", new String[]{userName, userId, token, tokenSecret}); //$NON-NLS-1$
    	SharedPreferences sp = context.getSharedPreferences(PREFS_NAME,
				Context.MODE_PRIVATE);
		Editor editor = sp.edit();
		editor.putString(KEY_OAUTH_TOKEN, token);
		editor.putString(KEY_TOKEN_SECRET, tokenSecret);
		editor.putString(KEY_USER_NAME, userName);
		editor.putString(KEY_USER_ID, userId);
		editor.commit();
    }
	
	public void uploadPhoto(IDataReadyListener callback, Bitmap bitmap, 
			String title, String description, boolean showProgress) {
		this.callbackUploadPhoto = callback;
		OAuth oauth = getOAuthToken();
		if (oauth != null && oauth.getUser() != null) {
			new UploadPhotoTask(this, bitmap,  title,  description, 
					showProgress, context).execute(oauth);
		}
	}
	// callback method after loadPhotolist asynchron
	@Override
	public void onPhotoUploaded(String resultUpload) {
		this.resultUpload = resultUpload;
		if (callbackUploadPhoto != null) {
			callbackUploadPhoto.onDataReady(true);
		} 
	}
	// return resultUpload from Data-Store
	public String getResultUpload() {
		return resultUpload;
	}



    
    
}
